package com.kyd.jpa.uid.utils;

import com.kyd.jpa.uid.baidu.utils.NetUtils;
import com.kyd.jpa.uid.twitter.SnowflakeIdWorker;

import java.lang.management.ManagementFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * IdWorker
 *
 * @author kejw on 2018/11/6
 */
public class IdWorker {
	private static final String GROUP_NAME = "uid-snowflake";
	private static Map<String, SnowflakeIdWorker> generatorMap = new ConcurrentHashMap<>();


	public static long nextId() {
		return getSnowflakeId().nextId();
	}

	public static String parseUID(Long uid) {
		return getSnowflakeId().parseUID(uid);
	}

	/**
	 * 获取ID生成器
	 *
	 * @return
	 */
	private static SnowflakeIdWorker getSnowflakeId() {
		SnowflakeIdWorker snowflakeIdWorker = generatorMap.get(GROUP_NAME);
		if (null == snowflakeIdWorker) {
			synchronized (generatorMap) {
				// 数据中心id--默认取机器码
				Long realDid = getMachineNum(31);
				// 机器id--默认取进程id
				long realWid = getProcessNum(realDid, 31);

				snowflakeIdWorker = new SnowflakeIdWorker(realWid, realDid);
				snowflakeIdWorker.setClock(true);
			}
		}

		return snowflakeIdWorker;
	}

	/**
	 * 获取机器码
	 *
	 * @param maxId 最大值
	 */
	private static long getMachineNum(long maxId) {
		byte[] mac = NetUtils.getMachineNum();
		long id = 0L;
		if (mac == null) {
			id = 1L;
		} else {
			id = ((0x000000FF & (long)mac[mac.length - 1]) | (0x0000FF00 & (((long)mac[mac.length - 2]) << 8))) >> 6;
			id = id % (maxId + 1);
		}
		return id;
	}

	/**
	 * 获取 进程id
	 *
	 * @param dataCenterId 数据中心id
	 * @param maxWorkerId 最大机器id
	 */
	private static long getProcessNum(long dataCenterId, long maxWorkerId) {
		StringBuilder mpid = new StringBuilder();
		mpid.append(dataCenterId);
		String name = ManagementFactory.getRuntimeMXBean().getName();
		if (null != name && !"".equals(name)) {
			mpid.append(name.split("@")[0]);// 获取 jvmPid
		}
		// dataCenterId + PID 的 hashcode 获取16个低位
		return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
	}

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			long uid = IdWorker.nextId();
			System.out.println(uid);
			System.out.println(IdWorker.parseUID(uid));
		}
	}
}
